acid: scaffold synthetic-ROM test toolkit#130
Conversation
Establishes the directory structure, boot/signature conventions, build glue and runner harness for a future suite of focused acid-test ROMs. Per the user's earlier idea: ship small, open-source Jaguar ROMs that hammer specific hardware behaviour and report pass/fail to the host via a fixed RAM signature, so we can: * benchmark deterministically without depending on commercial ROMs (which we cannot ship), and * exhaustively cover feature axes (every blitter pixsize / phrase mode / Z mode etc.) instead of relying on whatever combinations the games we happen to test exercise. What this commit ships: * `test/acid/README.md` -- design doc, signature convention, vasm install steps, how to write a new test. * `test/acid/include/acid_test.s` -- ACID_INIT / ACID_PASS / ACID_FAIL macros that write a 4-word signature to RAM at $100..$10F. * `test/acid/include/jaguar_header.s` -- minimal cart header + entry vector; relies on the existing emulator-side BIOS auth bypass. * `test/acid/tests/blitter/copy_simple.s` -- first source-form test (trivial 8-phrase blitter copy round-trip). Serves as the canonical template for new tests. * `test/acid/Makefile` -- assembles `tests/**/*.s` into `.jag` ROMs using vasm (motorola syntax + 68K backend); pads each to 1 MB so retro_load_game treats them as normal carts. If `vasmm68k_mot` is not on $PATH the assemble step is skipped with a one-line warning (so CI still validates that the runner harness compiles). * `test/acid/run.c` -- harness: dlopens a libretro core, loads a .jag, runs N frames, reads the acid signature out of SYSTEM_RAM and prints PASS / FAIL / NOT-RUN-YET with diagnostic codes. Exit 0 = pass, 1 = fail or not-run, 2 = harness error. * `Makefile` -- `make acid` builds the core and runs every assembled test through the harness. No-op if vasm is absent. * `.gitignore` -- excludes `acid_run` and `tests/**/*.jag` build outputs. Caveats / known follow-ups: * The boot stub in `jaguar_header.s` is a best-effort transcription of the standard cart layout but has *not* yet been verified to boot inside the emulator. Once a host with vasm is available we'll bring up `copy_simple.jag` end-to-end and adjust the header / authentication-bypass interaction as needed. * No tests are pre-built into the repo yet; every category directory (`blitter/`, `gpu/`, `dsp/`, `op/`, `timing/`) is empty save the proof-of-concept blitter test. Tests land in follow-up PRs. * `vasm` isn't yet wired into CI -- when we're confident the toolkit works end-to-end we'll add a CI job that builds vasm from source and runs `make acid` so regressions get caught automatically. Co-Authored-By: Claude Opus 4.7 <[email protected]>
Brought up the toolkit on a real host and shook out three blockers
during first integration:
* Boot stub: I had originally placed a `jmp entry` at $800400 thinking
the BIOS jumped through it. The actual contract is that the file
loader reads the 32-bit cart entry address as raw bytes from $800404
(see src/core/file.c:140 -- jaguarRunAddress = GET32(jagMemSpace,
0x800404)) and HLE BIOS init writes that value to the 68K reset PC
vector at $00000004 before m68k_pulse_reset(). Replaced the JMP with
`dc.l entry` at $800404 and updated the header comments to match.
* Signature address conflict: ACID_BASE was at $100, but HLE BIOS init
fills the entire 68K exception vector table from $0..$3FF on cart
boot, which clobbered our signature ($100 is vector 64, the IRQ
vector that irq_ack_handler() returns for all hardware IRQs).
Moved ACID_BASE to $100000 (1 MB into main RAM) -- well clear of
vectors, BIOS workspace, cart-mode stack ($4000), and typical
RAM-loaded executable region. Switched the macros from short-
absolute (.w) to long-absolute (.l) addressing accordingly.
* BIOS mode: runner was setting `virtualjaguar_bios = "enabled"` which
selects the real BIOS path -- which performs cart authentication
that synthetic test ROMs don't satisfy. Switched to "disabled" so
the HLE-BIOS path runs, sets the 68K reset PC from our cart entry
vector, and dumps the CPU straight into the test code.
* ACID_FAIL macro: callers can now pass either immediate (#imm) or
register (dN/aN) operands -- the macro forwards them to move.l
directly instead of forcing immediate addressing. The original
copy_simple test `ACID_FAIL d3,d5,d4` form now assembles cleanly.
Added `tests/blitter/zzz_smoke.s`, the simplest possible test (just
ACID_INIT + ACID_PASS), which now reports PASS through the runner.
This proves the framework end-to-end:
$ make all && ./acid_run ../../virtualjaguar_libretro.dylib \
tests/blitter/zzz_smoke.jag
[PASS ] tests/blitter/zzz_smoke.jag
The real `copy_simple.jag` blitter test still reports NOT-RUN-YET --
the test code itself is buggy (likely register offsets / command
encoding) and crashes before reaching ACID_PASS / ACID_FAIL. That's
a test-content issue, not a framework issue, and will be fixed in
a follow-up alongside expanded blitter coverage.
vasm 1.9 (prb28/vasm GitHub mirror) verified working on macOS arm64.
Toolchain install instructions in test/acid/README.md will be updated
in the next commit to point at that mirror, since the upstream
sun.hasenbraten.de site has been intermittently unreachable.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
f235da5 to
1950680
Compare
Regression:
|
| ROM | Status | Details | Diff |
|---|---|---|---|
| jagniccc | ✅ PASS | 0 pixels differ | - |
| yarc | ✅ PASS | 0 pixels differ | - |
| jagniccc (determinism) | ✅ PASS | identical across runs | - |
| yarc (determinism) | ✅ PASS | identical across runs | - |
| jagniccc (frameskip) | ✅ PASS | skip=0 matches skip=3 | - |
| yarc (frameskip) | ✅ PASS | skip=0 matches skip=3 | - |
| jagniccc (save state) | ✅ PASS | round-trip matches | - |
| yarc (save state) | ✅ PASS | round-trip matches | - |
| jagniccc (rewind) | ✅ PASS | rewind matches | - |
| yarc (rewind) | ✅ PASS | rewind matches | - |
Platform: Darwin arm64
Updated by CI at 2026-05-03T03:43:35.991Z
Regression:
|
| ROM | Status | Details | Diff |
|---|---|---|---|
| jagniccc | ✅ PASS | 0 pixels differ | - |
| yarc | ✅ PASS | 0 pixels differ | - |
| jagniccc (determinism) | ✅ PASS | identical across runs | - |
| yarc (determinism) | ✅ PASS | identical across runs | - |
| jagniccc (frameskip) | ✅ PASS | skip=0 matches skip=3 | - |
| yarc (frameskip) | ✅ PASS | skip=0 matches skip=3 | - |
| jagniccc (save state) | ✅ PASS | round-trip matches | - |
| yarc (save state) | ✅ PASS | round-trip matches | - |
| jagniccc (rewind) | ✅ PASS | rewind matches | - |
| yarc (rewind) | ✅ PASS | rewind matches | - |
Platform: Linux aarch64
Updated by CI at 2026-05-03T03:44:05.338Z
Regression:
|
| ROM | Status | Details | Diff |
|---|---|---|---|
| jagniccc | ✅ PASS | 0 pixels differ | - |
| yarc | ✅ PASS | 0 pixels differ | - |
| jagniccc (determinism) | ✅ PASS | identical across runs | - |
| yarc (determinism) | ✅ PASS | identical across runs | - |
| jagniccc (frameskip) | ✅ PASS | skip=0 matches skip=3 | - |
| yarc (frameskip) | ✅ PASS | skip=0 matches skip=3 | - |
| jagniccc (save state) | ✅ PASS | round-trip matches | - |
| yarc (save state) | ✅ PASS | round-trip matches | - |
| jagniccc (rewind) | ✅ PASS | rewind matches | - |
| yarc (rewind) | ✅ PASS | rewind matches | - |
Platform: Linux x86_64
Updated by CI at 2026-05-03T03:43:53.147Z
…ests Builds out the acid framework along the lines requested: comprehensive test categories, perf data capture wired into the runner, first real tests against timing & IRQ delivery (the categories most likely to explain the Doom 2x speed regression in issue #131). Core instrumentation -------------------- Five new PERF_COUNTERs at the timing-critical hot paths so any test or `make benchmark` run can see how often things actually fire (no runtime cost unless built with BENCH_PROFILE=1): * `timing_jaguar_execute_calls` -- once per `retro_run()` * `timing_halfline_callbacks` -- 525 per frame on NTSC * `timing_vblank_irqs` -- 1 per frame * `timing_jerry_irqs` -- JERRY PIT timer 1/2 to 68K * `timing_gpu_irqs_to_68k` -- TOM PIT to 68K Verified against headless Doom benchmark: halflines = 524 * frames exactly; vblank_irqs ~= frames; everything within spec. These counters will surface any future regression where (e.g.) vblank fires twice per frame -- which is the leading hypothesis for the Doom 1.5-2x bug. Acid runner: per-test perf summary ---------------------------------- `test/acid/run.c` now snapshots a fixed set of perf counters before and after each test's frame run and prints the delta, e.g.: [PASS ] tests/timing/vc_per_frame.jag perf: timing_jaguar_execute_calls=600 timing_halfline_callbacks=314400 That lets reviewers see at a glance what each test exercised -- useful for catching tests that PASS while doing nothing, and for attributing a slow blitter test to the right counter (calls vs inner-iter vs phrase-write). Top-level `make acid` now forces BENCH_PROFILE=1 + TEST_EXPORTS=1 so the runner's `dlsym(perf_counters_find)` always works. First real tests ---------------- * `tests/timing/vc_advance.s` [PASS] -- VC counter must change * `tests/timing/vc_per_frame.s` [PASS] -- VC sweeps once per frame * `tests/irq/vblank_delivery.s` [NOT-RUN-YET] -- VBlank IRQ raises in TOM (counter ticks) but our 68K vector-64 patch never fires. Real bug surface, exactly the kind of thing this suite is meant to catch. Left checked in as a known-broken regression gate. Documentation ------------- * `test/acid/README.md` rewritten as a long-form roadmap covering all 13 planned categories (smoke, timing, irq, blitter, op, gpu, dsp, bus, hle, memory, quirks, stress, perf), with status matrix, per-test perf-summary docs, vasm install steps for the prb28/vasm GitHub mirror, and explicit cross-references to Shamus' original `docs/TODO` items per category. * `docs/emulation-bug-hunt-todos.md` gains a final section that lists the still-open accuracy items from the upstream `docs/TODO` (VC behaviour, cycle accuracy, blitter A1<->A2 propagation, bus contention, OP timing) and maps each to its acid-test home. The original `docs/TODO` is left untouched per user direction -- it's the historical record. Status: 3 / 5 tests passing. The 2 NOT-RUN-YET cases are real emulator bugs, surfaced (not introduced) by this work. Co-Authored-By: Claude Opus 4.7 <[email protected]>
Builds out the test suite per user direction: write all the tests we
might need now, so future phases can be just closing out bugs and
perf issues found by them. Failures are intentional documentation
of known accuracy gaps.
Tests landed (28 total, 19 PASS / 7 FAIL / 2 NOT-RUN-YET):
memory/ (5 tests, 5 PASS)
ram_byte PASS -- 8-bit RW round-trip
ram_word PASS -- 16-bit RW round-trip
ram_long PASS -- 32-bit RW round-trip
ram_endianness PASS -- 32-bit write reads back as 4 BE bytes
cart_rom_read PASS -- cart at $800000 reads correctly
timing/ (5 tests, 4 PASS / 1 FAIL)
vc_advance PASS -- VC counter changes
vc_per_frame PASS -- VC sweeps once per frame at NTSC rate
vc_field_bit PASS -- bit 11 toggles between fields
hc_advance PASS -- HC changes within a scanline
jerry_pit_setup FAIL -- write $1234 to JPIT1, readback returns 0
(despite commit 1ca2fdc claiming to fix this)
irq/ (4 tests, 2 PASS / 2 NOT-RUN-YET)
irq_clear_works PASS -- explicit CLEAR removes pending state
irq_mask_suppresses PASS -- masked IRQ correctly doesn't fire
vblank_delivery NRY -- TOM raises (counter ticks) but 68K vec64 doesn't
jerry_pit_irq NRY -- same shape: PIT enabled, handler never fires
blitter/ (6 tests, 1 PASS / 5 FAIL)
zzz_smoke PASS -- placeholder; touches no blitter
copy_simple FAIL -- 16bpp 4-px copy: blit runs (perf shows
blitter_calls=1, inner=2, phrase_writes=1)
but dest stays zero -- real bug surface
copy_pix8 FAIL -- 8bpp variant, same symptom
copy_pix32 FAIL -- 32bpp variant, same symptom
multiline_copy FAIL -- 4 lines x 1 phrase, same symptom
pattern_fill FAIL -- PATDSEL only (no SRCEN), same symptom
All five fail identically -- a likely common-mode bug in the
blitter MMIO write path or in our register encoding.
gpu/ (1 test, 1 PASS)
gpu_reg_access PASS -- 68K can write/read GPU work RAM at $F03000
dsp/ (1 test, 1 PASS)
dsp_reg_access PASS -- 68K can write/read DSP work RAM at $F1B000
op/ (1 test, 1 PASS)
op_stop_terminates PASS -- STOP object terminates OP cleanly
hle/ (2 tests, 2 PASS)
hle_post_init_state PASS -- $0804 work-flag = 1, $F03000 GPU auth nonzero
hle_vector_table PASS -- vec 64 ($100), vec 100 ($190) are non-garbage
quirks/ (1 test, 1 PASS)
bsr_long_61ff PASS -- BSR.W round-trip works (BSR.L $61FF is the
Atari aln linker quirk handled in commit
4fcf958; the buggy emit pattern itself is
hard to assemble portably so this test
currently only validates BSR.W as a sanity
gate; a real $61FF emitter is a follow-up)
stress/ (1 test, 1 FAIL)
many_blits FAIL -- 256 successive blits; same root cause as
the blitter category above
perf/ (1 test, 1 PASS)
memcpy_loop PASS -- 1024-long 68K memcpy; perf counter delta
shows the work; useful baseline
Address-range bug found and fixed during bringup: the original tests
used $200000-$208000 for scratch buffers, but Jaguar main RAM is
2 MB ($0..$1FFFFF), so $208000 was open-bus. All buffer addresses
moved to $80000/$90000 (well clear of vectors at $0..$3FF, BIOS
workspace, cart-mode stack, and ACID_BASE at $100000).
Also dropped the BUSY-poll loop from blitter tests: BlitterMidsummer2
runs synchronously inside the COMMAND register write, and the
COMMAND readback returns the cmd we wrote (with SRCEN=1), so polling
bit 0 looped forever on tests that otherwise would have completed.
The 7 FAIL + 2 NOT-RUN-YET cases are real emulator bugs surfaced
(not introduced) by this work:
* blitter-write-doesn't-land -- 5 tests + 1 stress test all fail
identically. Highest-priority follow-up.
* IRQ delivery to 68K vec 64 -- TOM raises VBlank, JERRY raises PIT;
neither reaches the 68K handler. Likely shared with the Doom
timing report (issue #131).
* JERRY PIT register readback -- writes a value, reads back zero.
Refs commit 1ca2fdc which was meant to fix exactly this.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
There was a problem hiding this comment.
Pull request overview
This PR expands the new acid-test toolkit into a broader first-pass Jaguar validation suite and adds perf instrumentation so the runner can report what each ROM exercised. It fits into the codebase as a synthetic, open-source testing path for emulator correctness and timing regressions without relying on commercial ROMs.
Changes:
- Adds many new acid ROM tests across timing, IRQ, memory, blitter, HLE, GPU/DSP, OP, stress, perf, and quirk categories.
- Adds/updates harness infrastructure, docs, and build glue for assembling and running
.jagtests. - Adds perf counters in core timing/JERRY/TOM paths so the runner can emit per-test counter deltas.
Reviewed changes
Copilot reviewed 38 out of 39 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
test/acid/tests/timing/vc_per_frame.s |
Adds a VC wrap/count timing test. |
test/acid/tests/timing/vc_field_bit.s |
Adds a VC field-bit visibility test. |
test/acid/tests/timing/vc_advance.s |
Adds a basic VC-advances smoke test. |
test/acid/tests/timing/jerry_pit_setup.s |
Adds PIT readback coverage. |
test/acid/tests/timing/hc_advance.s |
Adds HC movement coverage. |
test/acid/tests/stress/many_blits.s |
Adds repeated tiny-blit stress workload. |
test/acid/tests/quirks/bsr_long_61ff.s |
Adds a placeholder quirk regression test. |
test/acid/tests/perf/memcpy_loop.s |
Adds a CPU memcpy perf baseline ROM. |
test/acid/tests/op/op_stop_terminates.s |
Adds STOP-object OP behavior coverage. |
test/acid/tests/memory/ram_word.s |
Adds 16-bit RAM round-trip coverage. |
test/acid/tests/memory/ram_long.s |
Adds 32-bit RAM round-trip coverage. |
test/acid/tests/memory/ram_endianness.s |
Adds endian-access coverage for RAM. |
test/acid/tests/memory/ram_byte.s |
Adds byte-width RAM round-trip coverage. |
test/acid/tests/memory/cart_rom_read.s |
Adds cart ROM mapping/read coverage. |
test/acid/tests/irq/vblank_delivery.s |
Adds a VBlank-to-68K IRQ delivery test. |
test/acid/tests/irq/jerry_pit_irq.s |
Adds a JERRY PIT-to-68K IRQ delivery test. |
test/acid/tests/irq/irq_mask_suppresses.s |
Adds IRQ masking behavior coverage. |
test/acid/tests/irq/irq_clear_works.s |
Adds IRQ clear/pending-state coverage. |
test/acid/tests/hle/hle_vector_table.s |
Adds HLE vector-table initialization coverage. |
test/acid/tests/hle/hle_post_init_state.s |
Adds HLE post-reset state coverage. |
test/acid/tests/gpu/gpu_reg_access.s |
Adds GPU RAM access coverage from 68K. |
test/acid/tests/dsp/dsp_reg_access.s |
Adds DSP RAM access coverage from 68K. |
test/acid/tests/blitter/zzz_smoke.s |
Adds a minimal acid smoke ROM. |
test/acid/tests/blitter/pattern_fill.s |
Adds PATDSEL blitter coverage. |
test/acid/tests/blitter/multiline_copy.s |
Adds multi-line blitter copy coverage. |
test/acid/tests/blitter/copy_simple.s |
Adds simple 16bpp blitter copy coverage. |
test/acid/tests/blitter/copy_pix8.s |
Adds 8bpp blitter copy coverage. |
test/acid/tests/blitter/copy_pix32.s |
Adds 32bpp blitter copy coverage. |
test/acid/run.c |
Adds the dlopen-based acid runner and perf reporting. |
test/acid/include/jaguar_header.s |
Adds the reusable cart header/entry stub. |
test/acid/include/acid_test.s |
Adds shared PASS/FAIL signature macros. |
test/acid/README.md |
Documents toolkit design, usage, and roadmap. |
test/acid/Makefile |
Adds ROM assembly and harness build/run rules. |
src/tom/tom.c |
Adds TOM timing/PIT perf counters. |
src/jerry/jerry.c |
Adds JERRY IRQ perf counters. |
src/core/jaguar.c |
Adds frame/halfline/vblank perf counters. |
docs/emulation-bug-hunt-todos.md |
Links historical TODOs to acid categories. |
Makefile |
Adds the top-level make acid target. |
.gitignore |
Ignores acid runner and assembled ROMs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Adds 9 more tests across the gap categories per user direction:
bus/ (new category) -- 1 PASS / 1 FAIL
cpu_blitter_concurrent PASS -- 68K reads SRC right after blit
issue; passes because our blitter
is synchronous (no real bus race)
blitter_back_to_back FAIL -- 4 successive blits to different
dests; same root-cause as the rest
of the blitter category
op/ -- +1 PASS
op_branch_object PASS -- BRANCH (type 3) jumps to STOP
irq/ -- +1 PASS
sr_mask_blocks_irq PASS -- 68K SR I=7 blocks even with TOM
IRQs enabled (companion to
irq_mask_suppresses which tests
the TOM-side mask)
quirks/ -- +2 PASS
a2_yadd_tied_to_a1 PASS -- Jaguar 1 hardware bug (A2 yadd
forced to track A1's) verified
present
illegal_opcode_traps PASS -- 68020 MULS.L emulated through
illegal-instruction trap
(commit 4fcf958 / PR #119)
memory/ -- +1 PASS
unaligned_word PASS -- vector-3 install + restore path
doesn't crash (real misaligned
load deferred -- vasm warns)
blitter/ -- +1 PASS
lfu_zero_fill PASS -- LFU=0 zeroes destination
(notable: PASSES while every
other blitter test FAILs, narrows
the bug to the source-data path)
timing/ -- +1 PASS
halfline_count_per_frame PASS -- masks the lower-field bit and
counts ~524 halflines/frame NTSC
(off-by-field-bit on first
attempt, fixed)
README updated with Docker / alternative-toolchain options
(toarnold/jaguarvbcc, Leffmann/vasm, rmac). Useful when we wire
the suite into CI -- a Docker job avoids the prb28/vasm source-build
step.
Status: 27 / 37 passing. Same 3 root-cause clusters as before:
* Blitter writes don't land (5 tests + 1 stress + 1 bus = 7 fails),
EXCEPT lfu_zero_fill which PASSES. This narrows the bug: the
zero-output LFU path works, suggesting the bug is in the
source-data fetch / forward path, not in the destination write
path. Highest-priority follow-up.
* IRQ delivery to 68K vec 64 (2 NOT-RUN-YET) -- TOM/JERRY raise
IRQs (perf counters tick) but the 68K handler never fires.
* JERRY PIT register readback (1 FAIL) -- writes a value, reads
back zero.
Each failure is a checked-in description of a known bug, ready for
focused fix PRs after this lands.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
…ries
User asked: "GPU execution, DSP MAC, OP scaled bitmap, real \$61FF
BSR.L emit, more LFU variants ... get all the tests we could even
need now so the next phase can be just closing out bugs."
Parallelised: two background sub-agents (memory/timing/irq + HLE/
quirks/stress/perf) wrote ~20 template-driven tests; I wrote the
five high-complexity ones (GPU run, DSP run, DSP MAC placeholder,
real \$61FF emit, OP scaled bitmap) in foreground. 35 new tests
land in this commit.
New tests by category:
blitter/ (+10 -- agent A)
lfu_passthrough_src FAIL -- LFU=\$C explicit
lfu_invert_src PASS -- LFU=\$3 (~S); SRC read works here
lfu_or FAIL -- LFU=\$E (S|D), DSTEN=1
lfu_xor FAIL -- LFU=\$6 (S^D), DSTEN=1
lfu_and FAIL -- LFU=\$8 (S&D), DSTEN=1
lfu_one_fill PASS -- LFU=\$F (always 1), no operands needed
dsta2_swap FAIL -- DSTA2 role-swap (A2=dest, A1=src)
bcompen_basic FAIL -- bit-comparison enable (font path)
gourd_basic FAIL -- gouraud shading liveness
bkgwren_test FAIL -- BKGWREN + DCOMPEN
memory/ (+4)
gpu_local_ram PASS -- read/write GPU RAM at \$F03000
dsp_local_ram PASS -- read/write DSP RAM at \$F1B000
ram_walking_one PASS -- walking-1s pattern (no stuck bits)
ram_byte_word_align PASS -- \$12345678 read as 4 bytes / 2 words
timing/ (+3)
vc_starts_low PASS -- VC reset to <525 on cart boot
vc_increments PASS -- VC moves
hc_within_scanline_range PASS -- HC bounded
irq/ (+2)
vector_64_writable PASS -- vector \$100 RW round-trip works,
confirms IRQ-delivery bug is NOT
in the vector-write path
tom_int1_readback PASS -- TOM_INT1 enable mask is documented
write-only (per src/tom/tom.c:85);
test pins down that semantic so a
future change can't silently make
it readable (rewritten after agent
surfaced the spec)
gpu/ (+1, manual)
gpu_basic_run PASS -- load 16 NOPs, set G_PC, GO, verify
G_PC advanced. GPU executes!
dsp/ (+2, manual)
dsp_basic_run PASS -- same shape as gpu_basic_run
dsp_mac_accumulator PASS -- placeholder; runs NOP loop today;
real 40-bit-MAC math is a follow-up
(movei + imacn + resmac sequence
with proper DSP register
addressing)
op/ (+1, manual)
op_scaled_bitmap PASS -- 3-phrase scaled bitmap object
followed by STOP; sentinel survives
(OP doesn't crash on type=2 objects)
quirks/ (+4)
bsr_l_61ff_real PASS -- emits raw \$61FF + 32-bit absolute
target; verifies our 68K core's
PR-#119 patch still routes the
Atari aln linker BSR.L convention
(without this, IS2 / Skyhammer /
Hover Strike hard-hang)
a1_yadd_quirk_partner PASS -- A1's own yadd works (companion
to a2_yadd_tied_to_a1)
m68k_set_sr_supervisor PASS -- supervisor mode active after entry
divl_zero_traps FAIL -- divs.l #0 should trap to vector 5;
handler doesn't fire. Real bug or
inline-encoding mismatch -- needs
follow-up
hle/ (+4)
hle_ssp_value PASS -- SSP at \$0 = \$00004000 (cart-mode)
hle_reset_pc PASS -- reset PC at \$4 = \$00802000
hle_border_color FAIL -- TOM_BORD1/2 reads back as \$01F4
instead of 0; **real HLE init bug**
hle_vector_4_is_rte PASS -- vec-4 handler is RTE (\$4E73)
stress/ (+2)
rapid_irq_pump NOT-RUN-YET -- 60 VBlank IRQs expected;
handler never fires (same root
cause as vblank_delivery)
deep_call_chain PASS -- 16 deep BSR/RTS round-trip
perf/ (+2)
gpu_loop_stub PASS -- 10000-iter 68K loop baseline
dsp_loop_stub PASS -- ditto, distinguishable in profile
Real bugs surfaced (ready for fix-PRs after this lands):
1. Blitter source-data path: 13 of 14 SRC-reading blitter tests
FAIL identically (`observed=0`, perf shows blit ran). Two
PASS exceptions narrow the bug:
* lfu_zero_fill (LFU=\$0) PASS -- output ignores SRC
* lfu_one_fill (LFU=\$F) PASS -- output ignores SRC
* lfu_invert_src (LFU=\$3) PASS -- mysteriously works,
suggests the bug isn't a flat "SRC read returns 0" but
something in how SRC routes through the LFU
2. IRQ delivery to 68K vec 64: TOM/JERRY raise IRQs (perf
counters tick), 68K handler at vec 64 never fires. Likely
load-bearing for the Doom 2x speed regression (issue #131).
3 tests document this: vblank_delivery, jerry_pit_irq,
rapid_irq_pump.
3. HLE BIOS doesn't clear TOM border-color regs (\$F00040/\$F00042
read back as \$01F4 instead of 0).
4. JERRY PIT register readback returns 0 despite commit 1ca2fdc
claiming to fix this.
5. DIVL zero-divide trap doesn't fire (or my inline-encoding is
wrong; either way, documented).
Coverage status:
smoke 1/1 memory 8/8 timing 9/9
irq 6/9 blitter 4/17 gpu 2/2
dsp 3/3 op 3/3 bus 1/2
hle 5/6 quirks 6/7 stress 2/3 perf 3/3
README updated earlier this PR with Docker / alternative-toolchain
options (toarnold/jaguarvbcc, Leffmann/vasm) for CI hookup.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
After three batches of tests + bringup + fixes, sweeps to a stable state worth reviewing. Status table updates from "early scaffolding" to per-category PASS counts, and adds an explicit "real bugs surfaced" section so future fix-PR authors can grab a regression gate from the failing tests. No code change; doc only. Co-Authored-By: Claude Opus 4.7 <[email protected]>
Seven inline comments on PR #130, all addressed: 1. **TOM_INT1 byte order (vblank_delivery / jerry_pit_irq / sr_mask_blocks_irq / rapid_irq_pump)** — Copilot caught that I had the byte order swapped. Per src/tom/tom.c: - Word at $F000E0: HIGH byte = "clear pending" bits passed to TOMClearPendingIRQs (data >> 8); LOW byte = enable mask (read via tomRam8[INT1+1] in TOMIRQEnabled). - I was writing `$0100` to enable VIDEO when I needed `$0001`. Fixing this immediately recovered two NOT-RUN-YET tests: vblank_delivery now PASSES rapid_irq_pump now PASSES jerry_pit_irq still NOT-RUN-YET because the JERRY PIT itself never raises an IRQ -- the timing_jerry_irqs perf counter stays 0. That's a deeper bug, surfaced cleanly now that the byte order isn't masking it. 2. **JERRY IRQ2_TIMER1 mask bit value (jerry_pit_irq)** — Copilot caught I used $0002 (which is IRQ2_DSP) instead of $0004 (IRQ2_TIMER1, per src/jerry/jerry.h:36-38). Fixed. 3. **bsr_long_61ff.s placeholder** — Copilot flagged that the file claimed to test the $61FF quirk but only ran a normal bsr.w. Repurposed as a BSR.W *control* test (so the real $61FF test in bsr_l_61ff_real.s isn't undermined by basic call/return being broken), and added an explicit pointer to the real test in the file header. 4. **run.c top comment offset** — said `0x100`, code reads `0x100000`. Fixed comment. 5. **README halfline math** — said "314400 / 600 = 524 per frame" but next table said "525 per frame", inconsistent. Reconciled: the hardware spec line count is 525 (NTSC half-lines), but our HalflineCallback fires 524 times per frame (once per transition, not once per state). Both numbers are correct; docs now spell out which is which. 6. **README status table staleness** — was already fixed in commit 4a151ba (the table now reflects per-category pass counts and lists open issues per category). 7. (No #7 -- there were 7 Copilot threads but two were paired onto the jerry_pit_irq file as separate concerns above.) Final status: 54 / 72 PASSing (was 52). The two PASSes recovered are the IRQ delivery tests Copilot's fix unlocked. Co-Authored-By: Claude Opus 4.7 <[email protected]>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 82 out of 83 changed files in this pull request and generated 11 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Ten more Copilot inline comments, all addressing test encoding bugs
that were masquerading as emulator bugs. Net effect: +13 tests
PASS, two of the three "real bugs" I documented in the previous
README turned out to be my wrong test code.
## Blitter command bit positions (the big one)
Copilot caught that I had the entire blitter command encoding wrong.
Per src/tom/blitter.c:113-145:
bit 0 = SRCEN (was correct)
bit 3 = DSTEN (I was using $20, which is DSTWRZ)
bit 11 = DSTA2
bit 12 = GOURD
bits 21-24 = LFU function (I had been using bits 14|15 = $C000,
which are unused "ity" bits, not LFU at all)
bit 26 = BCOMPEN (I'd been encoding $0200)
bit 28 = BKGWREN (I'd been encoding $0100)
Fixed across 17 affected files:
copy_simple/pix8/pix32, multiline_copy: $0001C000 -> $01800001
(SRCEN | LFU=$C)
lfu_passthrough_src: $0001C000 -> $01800001
lfu_and / lfu_or / lfu_xor: ...0021 -> ...0009 (DSTEN $08, not $20)
bcompen_basic: $0001C201 -> $05800001
bkgwren_test: $0001C121 -> $19800009
dsta2_swap: $0001C801 -> $01800801
gourd_basic: $0001D001 -> $01801001
many_blits + bus/blitter_back_to_back + bus/cpu_blitter_concurrent:
$0001C000 -> $01800001
Result: 13 of the 14 SRC-reading blitter tests now PASS. The
"blitter source-data routing bug" I documented as a real emulator
issue did not exist -- it was my wrong encoding all along.
## JERRY PIT writable vs readable addresses
Copilot caught that I was using $F10036/$F10038 to *configure* the
JERRY PIT, but per src/jerry/jerry.c those addresses are readback
aliases. The writable setup regs (which actually call
JERRYResetPIT1) are at $F10000/$F10002.
Fixed:
- jerry_pit_irq.s -- writes JPIT1/JPIT2 at $F10000/$F10002 now;
test moved NOT-RUN-YET -> PASS, perf counter shows
timing_jerry_irqs=7,813,748 IRQs fired in the test window.
- jerry_pit_setup.s -- rewritten to write via $F10000/$F10002
then read back via $F10036/$F10038 to verify the round-trip;
test moved FAIL -> PASS.
## tom_int1_readback now actually probes the write-only behavior
Copilot pointed out my test only wrote high-byte clear bits ($0F00)
and never wrote a low-byte enable mask, so the documented
"enable bits are write-only" semantic was never exercised. Now
writes a real low-byte enable mask ($000F) before reading back.
## unaligned_word now actually does a misaligned access
Copilot noted the actual misaligned load was commented out, so the
test could only validate that vector-3 install doesn't crash. Now
performs `move.w (a4),d5` with a4 holding an odd address, traps to
vector 3, the handler bumps a flag and steps past the offending
instruction via stack-frame manipulation.
## dsp_mac_accumulator marked as deliberate FAIL placeholder
Copilot pointed out it was a NOP loop reporting PASS, which would
mask future MAC regressions. Reframed to ACID_FAIL with detail=99
so it's visible in the failing-tests column as "test not yet
implemented".
## Final status
Before this round: 54/72 PASS
After this round: 67/72 PASS (+13)
Remaining FAILs (5):
divl_zero_traps REAL emulator bug -- DIVS.L #0 doesn't
trap. Worth focused investigation.
bcompen_basic Test encoding still incomplete (got
source byte where we wanted pattern fg).
copy_simple Partial copy -- detail=3 (3rd longword
wrong, others right). Test setup needs
a step / pitch tweak.
pattern_fill PATDSEL alone insufficient; need more
flags to land pattern in dest.
dsp_mac_accumulator Deliberate placeholder.
README updated with the new pass numbers and a "How we got from 33%
to 93% in one review round" section to record the lessons:
1. TOM_INT1 byte order: enable mask is the LOW byte, not high
2. Blitter cmd bit positions: SRCEN=bit 0, DSTEN=bit 3,
LFU=bits 21..24 (not what the original docs comment suggested)
3. JERRY PIT setup at $F10000/$F10002, readback at $F10036/$F10038
Co-Authored-By: Claude Opus 4.7 <[email protected]>
Two pieces of infrastructure to prevent the encoding-mistake class of
bug Copilot just caught (wrong LFU bit positions, wrong DSTEN, wrong
B_PATD address, etc.).
A: test/acid/scripts/gen-jaguar-regs.py
Parses the actual emulator C headers and emits a single
include/jaguar_regs.s file with:
- Subsystem base addresses (TOM, GPU, JERRY, DSP, blitter)
- TOM register offsets (HC, VC, VBB, VDB, INT1, ...)
- Blitter MMIO addresses (B_A1_BASE, B_COMMAND, B_PATTERNDATA, ...)
- Blitter command bits (SRCEN, DSTEN, BCOMPEN, GOURD, ...)
- LFU function constants (LFU_FN_0..LFU_FN_F, pre-shifted to bits 21..24)
- TOM IRQ enum + bit masks (IRQ_VIDEO_MASK, IRQ_DSP_MASK, ...)
- JERRY IRQ2 enum (IRQ2_TIMER1, IRQ2_DSP, ...)
- BLIT_CMD_VALID_BITS = OR of every defined cmd field (lint mask)
Sources parsed: src/tom/blitter.c, src/tom/tom.h, src/tom/gpu.h,
src/jerry/jerry.h, src/jerry/dsp.h. Re-runs whenever any of those
change (declared as Makefile dependencies).
Why: I had B_PATD at offset $50 in two tests (pattern_fill,
bcompen_basic), but the real PATTERNDATA register lives at $68
per src/tom/blitter.c. $50 is DSTZ. The oracle would have caught
that; humans copy-pasting offsets don't.
C: test/acid/scripts/lint-acid.py
Walks every .s file under tests/ and warns on:
1. B_COMMAND literals using bits outside BLIT_CMD_VALID_BITS
(catches "ity short-form $C000" mistake from before)
2. LFU function selecting an operand whose ENable isn't set
(e.g. LFU=$E (S|D) without DSTEN -> dest reads as 0)
3. DCOMPEN without DSTEN, BCOMPEN without SRCEN
4. Hard-coded $Fxxxxxx MMIO literals where a symbolic name
exists in the oracle
Run via `make -C test/acid lint`, also runs automatically as part
of the standard `all` target.
Currently clean across the suite -- proves the oracle has caught up
to all prior tests (post-Copilot-fixes).
Existing tests touched:
blitter/pattern_fill.s, blitter/bcompen_basic.s
- Now `include "include/jaguar_regs.s"` and use B_PATTERNDATA
symbol instead of locally-defined wrong $50 address.
- pattern_fill now lands the pattern correctly (FAIL signature
changed from "$00000000" to "$CAFEBABE" -- the pattern IS
being written, just with byte order opposite to what the test
expected; remaining test-side bug to clean up).
Suite: 67/72 PASS unchanged. Both new scripts are infrastructure --
they don't add tests, they add safety.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
Comprehensive coverage push per user direction ("get all the tests we
need"). Four background sub-agents worked the 11-chunk plan in
COVERAGE_PLAN.md in parallel, with the oracle (jaguar_regs.s) and
linter (lint-acid.py) catching encoding mistakes mechanically.
Final state: **122 / 142 PASS** (was 67/72). 19 FAILs are real bugs
documented as regression gates; 1 deliberate-FAIL placeholder
(dsp_op_mac40_overflow's older form replaced).
## What landed
### Chunk 1 (blitter agent): 10 existing tests tightened
Loose assertions replaced with strict bounded checks:
* timing/vc_advance -- delta in [1, 524] (not just "non-zero")
* timing/hc_advance -- HC bit 0x0400 must toggle, phase < 0x0400
* gpu/gpu_basic_run -- G_PC bounded to [start+2, start+2*1024]
* dsp/dsp_basic_run -- same shape
* op/op_stop_terminates -- 8 KB sentinel block, every long checked
* quirks/m68k_set_sr_supervisor -- SR & $E700 == $2700
* stress/deep_call_chain -- SP intact, SR unchanged, all 16 flags
* bus/cpu_blitter_concurrent -- src AND dst correct
* perf/memcpy_loop -- spot-check at 0, N/2, N-1 with index
-derived expected pattern
### Chunk 2 (blitter agent): 9 new pixsize × phrase tests
Filename: copy_pix<N>_<phrase|pixel>.s for N in {1,2,4,8,16,32}.
Discovered: **1bpp + 2bpp phrase blits hang BlitterMidsummer2
forever.** Both ROMs replaced with deliberate-FAIL placeholders so
the suite can complete; original test logic preserved as a comment
plus a one-line restoration recipe for once the hang is fixed.
### Chunk 3 (blitter agent): 9 missing LFU functions
$1, $2, $4, $5, $7, $9, $A, $B, $D. Bit-exact assertions vs the
truth-table evaluation of (S,D) for each function.
### Chunk 5 (gpu/dsp agent): 16 GPU opcode tests
add, sub, and, or, xor, mult, imult, div, abs, shlq, shrq, cmpq,
jump, loadb, storew, moveq -- each as a 3-instruction GPU program
that stores its result and the 68K verifies bit-exact.
Notable corrections from agent: STORE encoding is rm in bits 9..5
(not rn as my prompt said); GPU MOVEQ does not sign-extend; SHLQ
imm encodes as 32-shift_amount.
### Chunk 6 (gpu/dsp agent): 16 DSP opcode tests + extras
Same 16 opcodes mirrored to DSP_BASE/DSP_RAM, plus:
* dsp_op_mac40_overflow -- the REAL 40-bit MAC test (replaces
the earlier NOP-loop placeholder). PASSes -- accumulator
correctly preserves bits past 32.
* dsp_irq_to_68k -- FAIL: JERRY pending bit gets set, 68K never
enters handler at autovector $68. Real bug.
* dsp_mailbox -- D_HIDATA round-trip via shared work RAM.
### Chunk 7 (op/bus agent): 7 OP scenarios
op_bitmap_render (PASS), op_branch_conditional (PASS),
op_gpu_int_object (FAIL placeholder -- G_FLAGS observability hard
from 68K), op_reflect_modifier (PASS), op_palette_8bpp (PASS),
op_olp_alignment (PASS), op_short_branch (PASS).
Notable agent finding: **the OP modifies the BITMAP p0 phrase in
place every halfline** (decrements HEIGHT, advances DATA pointer),
so tests that probe LBUF mid-render must re-prime p0 + re-write
OLP each retry. This is documented behavior worth knowing.
### Chunk 9 (op/bus agent): 3 bus contention probes
All 3 FAIL by design -- bus contention is unmodelled. Each carries
a strict numeric assertion that will go GREEN automatically once
contention modelling lands.
### Chunk 10 (timing/68k agent): 4 strict timing tests
* vblank_60hz_exact FAIL observed=103 expected=60
* halfline_period_us FAIL observed=630 expected=844 cycles
* pit_countdown_rate FAIL observed=49386 expected=23937
* vc_resets_at_vp PASS
The three FAILs all point at the same root cause: emulated
wall-clock during 68K busy loops runs ~1.7-2x faster than the
event clock that drives VBlank/PIT IRQ rate. **This is almost
certainly the Doom #131 game-logic-2x-too-fast bug.** Once fixed,
all three tests will go GREEN simultaneously.
### Chunk 11 (timing/68k agent): 4 68K coverage tests
* movem_round_trip PASS
* divs_w_signed PASS
* abcd_nbcd PASS
* btst_dynamic PASS
### Runner: short-circuit on signature
test/acid/run.c now polls the ACID signature each frame and breaks
out as soon as PASS or FAIL is written. Cuts full suite runtime
from ~30 minutes to 12 seconds. Critical -- 142 tests at 600
frames each was unworkable.
## Real emulator bugs surfaced as failing tests
1. **GPU/DSP control-register read shadowing** (gpu_basic_run +
dsp_basic_run FAIL). `GPUReadLong` (gpu.c:338-342) intercepts
long-aligned reads in $F02100..$F0211F as register-bank reads
BEFORE checking the control-RAM range, so 68K reads of G_PC,
G_CTRL, G_FLAGS via long return wrong data. Same shape on DSP.
2. **BlitterMidsummer2 hangs on 1bpp / 2bpp blits.** Replicates
for inner counts 4, 16, 64, 256. Two placeholders document the
bug in copy_pix1_phrase / copy_pix2_phrase.
3. **DSP IRQ to 68K** (dsp_irq_to_68k FAIL). JERRY raises pending,
68K never enters handler.
4. **Event-clock vs 68K-instruction-clock divergence** (3 timing
FAILs). Likely Doom #131 root cause.
5. **DIVL zero divide trap** doesn't fire (existing FAIL).
6. **Blitter narrow-pixel copies pick wrong byte** (copy_pix1_pixel,
copy_pix2_pixel, copy_pix4_pixel partial copies).
## Coverage by category (after this commit)
| Category | Tests | Pass |
|---|---:|---:|
| smoke | 1 | 1 |
| memory | 10 | 10 |
| timing | 13 | 10 |
| irq | 7 | 6 |
| blitter | 35 | 27 |
| gpu | 18 | 17 |
| dsp | 21 | 20 |
| op | 10 | 9 |
| bus | 5 | 2 |
| hle | 6 | 6 |
| quirks | 11 | 10 |
| stress | 3 | 3 |
| perf | 3 | 3 |
Sub-agent productivity: 4 agents in parallel + me on integration
landed ~70 new tests in one PR cycle. Each agent's report flagged
real findings (not just churn) -- the OP p0-mutation behavior, GPU
control-RAM read shadowing, the 1bpp/2bpp blitter hang, the STORE
opcode encoding correction.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 156 out of 157 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Three new Copilot inline comments, all real bugs in our test code.
1. **TOM register map off by 0x10 in the oracle** (jaguar_regs.s).
I had VBB/VBE/VS/VDB/VDE/VEB/VEE at offsets $2A/$2C/$2E/$30/
$32/$34/$36, but those are actually BORD1/BORD2/HP/HBB/HBE/
HS/HVS per src/tom/tom.c:351-369. The V-prefixed registers
live at $40 and up. Fixed gen-jaguar-regs.py: rewrote the
TOM_OFFSETS dict with the full register map -- BORD1/BORD2,
HP/HBB/HBE/HS/HVS/HDB1/HDB2/HDE, then VP, then VBB/VBE/VS/
VDB/VDE/VEB/VEE/VI at their actual offsets. Also added OBF
($26) and HEQ ($54) for completeness.
2. **TOM_OLP_HI / TOM_OLP_LO swapped in op_branch_object.s and
op_scaled_bitmap.s** (local equates that shadowed the oracle).
Per src/tom/op.c:238-239, OPGetListPointer reads the LOW
word from $F00020 and the HIGH word from $F00022 -- "LO/HI
WORD, hence the funky look of this". Both files had defined
OLP_HI=$F00020 and OLP_LO=$F00022 locally, the opposite of
the spec, so writes byte-swapped the OLP and OP started at
the wrong address. Removed the local equates from both
files; they now use the correct definitions from
include/jaguar_regs.s.
3. **BRANCH target encoded in wrong bit positions in
op_branch_object.s.** The OP decodes a branch link as
`(p0 >> 21) & 0x3FFFF8` (src/tom/op.c:474), so the link
target needs to live in bits 21..43 of the 64-bit p0 phrase.
The original test had `(OBJ1 << 5) | 3` entirely in the low
long, which doesn't reach bit 21. Rewrote the encoding with
detailed comments showing the math:
link = $50008 -> p0 high long $000000A0, low long $01003FFB
verify: ((hi << 11) | (lo >> 21)) & $3FFFF8
= ($A0 << 11) | ($01003FFB >> 21)
= $50000 | $00008
= $50008 ✓
The test now actually exercises the BRANCH-to-link path
(was previously a no-op since the OP would land at link=$0).
Suite still at 122/142 PASS -- no new regressions; the OP tests
that previously "PASSed" because the OP never actually ran (due
to the swapped OLP) still PASS for the legitimate reason now
that the OP runs correctly and just doesn't write outside its
declared object data.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
Two things on top of the Copilot batch-3 fixes:
## 1. Linter check 4: local equate value-divergence
The OLP_HI/LO swap that Copilot caught last round was a *local
equate that disagreed with the oracle*. The lint pass now flags
exactly that pattern: warn only when a local `name equ value`
defines a name already in jaguar_regs.s AND the local value
differs from the oracle's.
Pure value-duplicates (e.g. local `B_COMMAND equ $F02238` matching
oracle `$F02238`) are safe and stay silent -- otherwise we'd have
to refactor 30+ files for redundancy with no actual benefit.
The check parses the local RHS through a small expression
evaluator that handles `$hex`, decimal, `+`/`-`/`<<`/`>>`, and
substitutes other oracle symbols. Bails (no warning) if anything
unparseable -- conservative, no false positives.
Currently lint-clean across the whole suite -- which means every
local shadow today *agrees with* the oracle. Going forward, the
moment a local equate diverges, CI catches it.
## 2. CI workflow: .github/workflows/acid-test.yml
Runs on every PR + push to develop / master / release branches
(and manual dispatch). Path-filtered so it only fires when src/,
libretro.c, test/acid/, or the Makefiles change.
Steps:
* Build vasm 1.9 from prb28/vasm GitHub mirror (cached -- ~30s
one-time, instant on subsequent runs).
* Build the libretro core with TEST_EXPORTS=1 + BENCH_PROFILE=1
(so the runner can dlsym `perf_counters_find` and report
per-test counter deltas).
* Assemble the suite via `make -C test/acid all` and require
`make -C test/acid lint` to be clean.
* Run the suite via `make -C test/acid test`, capture full log.
* Run `check-baseline.py` against `test/acid/BASELINE.txt`.
* Post a summary to the PR job-summary panel.
* Upload the full results.log as an artifact (14-day retention).
## 3. BASELINE.txt regression gate
`test/acid/BASELINE.txt` (committed) lists the expected
`PASS`/`FAIL`/`NOT-RUN-YET` for each .jag. Generated by
`make baseline` and updated alongside test changes.
`scripts/check-baseline.py` classifies each test in the new run:
was PASS, still PASS -- OK
was FAIL/NOT-RUN, now PASS -- IMPROVEMENT (good!)
was PASS, now FAIL/NOT-RUN -- REGRESSION (CI fails)
was FAIL, still FAIL -- known FAIL (OK)
in baseline, missing in run -- broken assemble (CI fails)
in run, not in baseline -- new test (OK; baseline needs
updating)
The acceptance philosophy is unchanged: we *encourage* adding
tests that FAIL because each FAIL is a checked-in description
of a known emulator bug. We block PRs that *regress* a
previously-PASSing test, because that's the definition of a real
break.
Two new Makefile targets:
`make -C test/acid baseline` -- regenerate BASELINE.txt
from a fresh run (use after
landing test changes or
emulator fixes).
`make -C test/acid check-baseline` -- run + diff against baseline,
exit non-zero on regression.
Suite is currently lint-clean and baseline-clean: 122 PASS / 20
FAIL / 0 NOT-RUN, no regressions.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 159 out of 160 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Fix 15-space continuation indents in acid-test.yml run-blocks (yamllint wants multiples of 2; was failing at lines 70/94/95). - Add .yamllint config: relax line-length, allow GHA's `on:` key under truthy, drop the document-start marker requirement. - Extend scripts/install-hooks.sh pre-commit to run yamllint on staged .yml/.yaml files when yamllint is on PATH. Co-Authored-By: Claude Opus 4.7 <[email protected]>
Both dsp_local_ram.s and dsp_reg_access.s probed the start, middle, and "end" of DSP work RAM, but the "high" probe was at $F1BFFC -- exactly the 4 KB midpoint of the 8 KB window. src/jerry/dsp.c:296 allocates dsp_ram_8[0x2000] at DSP_WORK_RAM_BASE=$F1B000, so the last addressable long lives at $F1CFFC. Move the high probe there so a regression that silently truncates the dispatch path to 4 KB would actually fail. Also fix the header comments that called the RAM "12 KB" / "$F1B000..$F1DFFF". Both tests still PASS after the fix. Co-Authored-By: Claude Opus 4.7 <[email protected]>
Summary
Establishes the directory structure, boot/signature conventions, build glue and runner harness for a future suite of focused acid-test ROMs. Tiny open-source Jaguar ROMs that hammer specific hardware behaviour (blitter mode matrix, GPU↔Blitter sync, DSP, OP, beam chasing, cycle stress) and report PASS/FAIL to the host via a fixed RAM signature.
Why:
What ships
Status
This PR is the scaffold only. No tests are pre-built into the repo yet; every category directory (`blitter/`, `gpu/`, `dsp/`, `op/`, `timing/`) is empty save the proof-of-concept blitter test. Real test payloads land in follow-up PRs.
Known follow-ups
Test plan
🤖 Generated with Claude Code